#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;

void *functionCount1(void *t);
void *functionCount2(void *t);

int count = 0;
int condition_count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6

// Write numbers 1-3 and 8-10 as permitted by functionCount2()
void *functionCount1(void *t)
{
	while (true)
	{
		// Lock mutex and then wait for signal to relase mutex
		pthread_mutex_lock(&count_mutex);
		printf("functionCount1 locked\n");

		// Wait while functionCount2() operates on count
		// mutex unlocked if condition variable in functionCount2() signaled.
		pthread_cond_wait(&condition_var, &count_mutex);
		printf("Counter value functionCount1: %d\n", ++count);
		pthread_mutex_unlock(&count_mutex);
		printf("functionCount1 unlocked\n");

		if (count >= COUNT_DONE)
			return (NULL);
	}

	return (NULL);
}

// Write numbers 4-7
void *functionCount2(void *t)
{
	while (true)
	{
		pthread_mutex_lock(&count_mutex);
		printf("functionCount2 locked\n");

		if (count < COUNT_HALT1 || count > COUNT_HALT2)
		{
			// Condition of if statement has been met.
			// Signal to free waiting thread by freeing the mutex.
			// Note: functionCount1() is now permitted to modify "count".
			pthread_cond_signal(&condition_var);
			printf("functionCount2 cond_signal %d\n", ++condition_count);
		}
		else
		{
			count++;
			printf("Counter value functionCount2: %d\n", count);
		}

		pthread_mutex_unlock(&count_mutex);
		printf("functionCount2 unlocked\n");

		if (count >= COUNT_DONE)
			return(NULL);
	}

	return (NULL);
}

// Main entry
int main(int argc, char *argv[])
{
	pthread_t thread1, thread2;
	pthread_attr_t attr;
	int rc;
	long t = 0;

	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	rc = pthread_create(&thread1, &attr, functionCount1, (void *)t);
	if (rc) exit(0);

	t++;
	rc = pthread_create(&thread2, &attr, functionCount2, (void *)t);
	if (rc) exit(0);

	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);

	printf("Final count: %d\n", count);

	exit(0);
}
